package com.kgc.personprovider.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.kgc.basic.util.PageInfo;
import com.kgc.basic.util.ResponseMsg;
import com.kgc.personcommon.pojo.Permission;
import com.kgc.personcommon.pojo.Role;
import com.kgc.personcommon.pojo.User;
import com.kgc.personcommon.util.CreateCode;
import com.kgc.personcommon.util.JwtUtil;
import com.kgc.personprovider.dao.RoleMapper;
import com.kgc.personprovider.dao.UserMapper;
import com.kgc.personprovider.service.UserService;
import com.kgc.personprovider.util.TreeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Transactional
public class UserServiceImpl implements UserService {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public ResponseMsg getByPage(Map<String, Object> params) {
        logger.info("UserServiceImpl getByPage, params:{}", params);
        ResponseMsg responseMsg = new ResponseMsg();
        PageHelper.startPage(Integer.valueOf(params.get("pageNow").toString()),
                Integer.valueOf(params.get("pageSize").toString()));
        List<User> list = userMapper.getAll(params);
        logger.debug("userMapper getUserPage, list:" + list + ", params:" + params);
        PageHelper.clearPage();

        int total = userMapper.getCount(params);
        logger.debug("userMapper getCount, total:" + total + ", params:" + params);

        PageInfo<User> pageInfo = new PageInfo<>();
        if (list != null && !list.isEmpty()) {
            pageInfo.setList(list);
            pageInfo.setPageNo(Integer.valueOf(params.get("pageNow").toString()));
            pageInfo.setPageSize(Integer.valueOf(params.get("pageSize").toString()));
            pageInfo.setTotal(total);
        }

        if (pageInfo.getList() != null && !pageInfo.getList().isEmpty()) {
            responseMsg.setCode("200");
            responseMsg.setData(pageInfo);
        } else {
            responseMsg.setCode("201");
        }
        return responseMsg;
    }

    @Override
    public ResponseMsg add(User user) {
        logger.info("UserServiceImpl add, user:{}", user);
        ResponseMsg responseMsg = new ResponseMsg();
        Date now = new Date();
        user.setCreateDate(now);
        user.setUpdateDate(now);
//        user.setCreateUser("admin");
//        user.setUpdateUser("111");

        int count = userMapper.addUser(user);
        logger.debug("userMapper addUser, count:" + count + ", user:" + user);
        if (count <= 0) {
            responseMsg.setCode("201");
            return responseMsg;
        }
        Map<String, Object> m = new HashMap<>();
        m.put("updateUser", user.getUpdateUser());
        m.put("updateDate", user.getUpdateDate());
        m.put("createUser", user.getCreateUser());
        m.put("createDate", user.getCreateDate());
        for (int rid : user.getRids()) {
            m.put("uid", (int) user.getId());
            m.put("cid", rid);
            userMapper.addUserRole(m);
            logger.debug("userMapper addUserRole, map:" + m);
        }

        responseMsg.setCode("200");
        return responseMsg;
    }

    @Override
    public ResponseMsg update(User user) {
        logger.info("UserServiceImpl update, user:{}", user);
        ResponseMsg responseMsg = new ResponseMsg();
        Date now = new Date();
        user.setUpdateDate(now);
//        user.setUpdateUser("111");

        int count = userMapper.updateUser(user);
        logger.debug("userMapper updateUser, count:" + count + ", user:" + user);
        if (count <= 0) {
            responseMsg.setCode("201");
            return responseMsg;
        }

        int uid = user.getId();
        int num =userMapper.delUserRoleByUser(uid+"");
        logger.debug("userMapper delUserRoleByUser, userId:" + uid+", num:" + num + ", user:" + user);
        Map<String, Object> m = new HashMap<>();
        m.put("uid", uid);
        for (int rid : user.getRids()) {
            m.put("cid", rid);
            int n = userMapper.addUserRole(m);
            logger.debug("userMapper addUserRole, map:" + m+", uid:" + uid+", num:" + n);
        }

        responseMsg.setCode("200");
        return responseMsg;
    }

    @Override
    public ResponseMsg delete(String id) {
        logger.info("UserServiceImpl delete, id:{}", id);
        ResponseMsg responseMsg = new ResponseMsg();
        int count = userMapper.deleteUser(id);
        logger.debug("userMapper deleteUser, count:" + count + ", id:" + id);
        if (count > 0) {
            responseMsg.setCode("200");
        } else {
            responseMsg.setCode("201");
        }
        return responseMsg;
    }

    @Override
    public ResponseMsg getById(String id) {
        logger.info("UserServiceImpl getById, id:{}", id);
        ResponseMsg responseMsg = new ResponseMsg();
        User user = userMapper.getUserById(id);
        logger.debug("userMapper getUserById, id:" + id + ", user:" + user);
        if (user != null) {
            responseMsg.setData(user);
            responseMsg.setCode("200");
        } else {
            responseMsg.setCode("201");
        }
        return responseMsg;
    }

    @Override
    public ResponseMsg getAll(Map<String, Object> params) {
        logger.info("UserServiceImpl getAll, params:{}", params);
        ResponseMsg responseMsg = new ResponseMsg();
        List<User> list = userMapper.getAll(params);
        logger.debug("userMapper getAllUsers, list:" + list + ", params:" + params);
        if (list != null && !list.isEmpty()) {
            responseMsg.setCode("200");
            responseMsg.setData(list);
        } else {
            responseMsg.setCode("201");
        }
        return responseMsg;
    }

    /**
     * 用户登录：验证码校验 → 用户校验 → 从 DB 分别加载菜单路由(type=1)和接口路径(type=2)
     * → 生成 JWT(只放接口路径) → Redis 缓存 token+permissions → 返回给前端 token、permissions、menuTree
     */
//    @Override
//    public ResponseMsg login(String account, String password, String checkCode) {
//        // 1. 校验验证码
//        String storedCode = redisTemplate.opsForValue().get("code");
//        if (storedCode == null || !storedCode.equalsIgnoreCase(checkCode)) {
//            return new ResponseMsg("303", "验证码错误", null);
//        }
//
//        // 2. 校验用户名密码
//        User user = userMapper.getUserByAccount(account);
//        if (user == null) {
//            return new ResponseMsg("301", "您还未注册", null);
//        }
//        if (!user.getPassword().equals(password)) {
//            return new ResponseMsg("302", "用户名或密码错误", null);
//        }
//
//        // 3. 从 DB 分别获取“组件路由” 和 “接口路径”
//        //    type=1 的菜单权限，用于前端左侧菜单
//        List<Permission> flatMenus = userMapper.findMenuPermissionsByUser(account);
//        //    递归组装成树（假设你有一个 TreeUtil.buildTree 方法）
//        List<Permission> menuTree = TreeUtil.buildTree(flatMenus, 0);
//
//        //    type=2 的接口权限，用于 JWT 权限校验
//        List<String> apiPaths = userMapper.getApiPathsByUser(account);
//
//        // 4. 生成 JWT，Claims 中只放接口路径列表
//        String token = jwtUtil.generateToken(account, apiPaths);
//        String refreshToken = jwtUtil.generateRefreshToken(account, apiPaths);
//        // 5. 写入 Redis，缓存 token 与接口列表
//        String tokenKey = "user:" + account + ":token";
//        String refreshKey = "user:" + account + ":refresh";
//        long expireSeconds = jwtUtil.getExpiration() / 1000;
//        redisTemplate.opsForValue().set(tokenKey, token, expireSeconds, TimeUnit.SECONDS);
////      redisTemplate.opsForValue().set(permsKey, JSON.toJSONString(apiPaths), expireSeconds, TimeUnit.SECONDS);
//        redisTemplate.opsForValue().set(refreshKey, refreshToken, expireSeconds * 2, TimeUnit.SECONDS);
//        // 6. 组装返回给前端的数据
//        Map<String, Object> data = new HashMap<>();
//        data.put("user", user);
//        data.put("token", token);
//        data.put("refreshToken", refreshToken);
//        data.put("permissions", apiPaths);
//        data.put("menuTree", menuTree);
//        data.put("company", user.getCompany());
//
//        return new ResponseMsg("200", "登录成功", data);
//    }
    @Override
    public ResponseMsg login(String account, String password, String checkCode) {
        // 1. 校验验证码
        String storedCode = redisTemplate.opsForValue().get("code");
        if (storedCode == null || !storedCode.equalsIgnoreCase(checkCode)) {
            return new ResponseMsg("303", "验证码错误", null);
        }

        // 2. 校验用户名密码
        User user = userMapper.getUserByAccount(account);
        if (user == null) {
            return new ResponseMsg("301", "您还未注册", null);
        }
        if (!user.getPassword().equals(password)) {
            return new ResponseMsg("302", "用户名或密码错误", null);
        }

        // 3. 获取菜单权限和接口权限
        List<Permission> flatMenus = userMapper.findMenuPermissionsByUser(account);
        List<Permission> menuTree = TreeUtil.buildTree(flatMenus, 0);
        List<String> apiPaths = userMapper.getApiPathsByUser(account);

        // 4. 生成不含权限的 token
        String token = jwtUtil.generateToken(account);
        String refreshToken = jwtUtil.generateRefreshToken(account);

        // 5. 缓存 token 和接口权限
        String tokenKey = "user:" + account + ":token";
        String refreshKey = "user:" + account + ":refresh";
        String permsKey = "user:" + account + ":permissions";
        long expireSeconds = jwtUtil.getExpiration() / 1000;

        redisTemplate.opsForValue().set(tokenKey, token, expireSeconds, TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(refreshKey, refreshToken, expireSeconds * 2, TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(permsKey, JSON.toJSONString(apiPaths), expireSeconds, TimeUnit.SECONDS);

        // 6. 返回数据
        Map<String, Object> data = new HashMap<>();
        data.put("user", user);
        data.put("token", token);
        data.put("refreshToken", refreshToken);
        data.put("permissions", apiPaths);
        data.put("menuTree", menuTree);
        data.put("company", user.getCompany());

        return new ResponseMsg("200", "登录成功", data);
    }


    @Override
    public String getCaptcha() {
        try {
            // 生成验证码
            String code = CreateCode.generateCode(4);
            redisTemplate.opsForValue().set("code", code, 60, TimeUnit.SECONDS);

            // 创建图片
            int width = 120, height = 40;
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = image.createGraphics();

            // 设置背景色
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, width, height);

            // 绘制干扰线
            Random random = new Random();
            for (int i = 0; i < 20; i++) {
                g.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));
                g.drawLine(random.nextInt(width), random.nextInt(height), random.nextInt(width), random.nextInt(height));
            }

            // 绘制验证码文字
            g.setFont(new Font("Arial", Font.BOLD, 24));
            for (int i = 0; i < code.length(); i++) {
                g.setColor(new Color(random.nextInt(128), random.nextInt(128), random.nextInt(128)));
                g.drawString(String.valueOf(code.charAt(i)), 25 * i + 10, 28);
            }

            // 将图片转换为 Base64 编码
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(image, "jpeg", baos);
            byte[] imageBytes = baos.toByteArray();
            String base64Image = Base64.getEncoder().encodeToString(imageBytes);
            return base64Image;
        } catch (Exception e) {
            logger.error("getCaptcha is error", e);
            return null;
        }
    }

    /**
     * 获取前端路由：从 JWT 中取接口权限列表，过滤出 type=1 菜单路由
     * 或者直接从 DB 重新读 menuTree，这里示范用 DB 重读。
     */
    @Override
    public ResponseMsg getUserRoutes(String account) {
        // 假设前端传 account，而非 token，因为菜单是 DB 维护
        List<Permission> flatMenus = userMapper.findMenuPermissionsByUser(account);
        if (flatMenus.isEmpty()) {
            return new ResponseMsg("204", "无可用路由", Collections.emptyList());
        }
        List<Permission> menuTree = TreeUtil.buildTree(flatMenus, 0);
        return new ResponseMsg("200", "获取路由成功", menuTree);
    }

    /**
     * 登出：删除 Redis 中的 token 和 perms
     */
    @Override
    public ResponseMsg logout(String account) {
        if (account == null || account.isEmpty()) {
            return new ResponseMsg("400", "账号不能为空", null);
        }

        String tokenKey = "user:" + account + ":token";
        String refreshKey = "user:" + account + ":refresh";
        String permsKey = "user:" + account + ":permissions";

        redisTemplate.delete(tokenKey);
        redisTemplate.delete(refreshKey);
        redisTemplate.delete(permsKey);

        return new ResponseMsg("200", "退出成功", null);
    }


    /**
     * 返回按树形组装的组件权限（type=1），也可以传 account 或 userId
     */
    @Override
    public ResponseMsg getTreePermissionsByUserId(String account) {
        List<Permission> flatMenus = userMapper.findMenuPermissionsByUser(account);
        if (flatMenus.isEmpty()) {
            return new ResponseMsg("404", "用户无权限", null);
        }
        List<Permission> menuTree = TreeUtil.buildTree(flatMenus, 0);
        return new ResponseMsg("200", "查询成功", menuTree);
    }

@Override
public ResponseMsg refresh(Map<String, String> map) {
    String refreshToken = map.get("refreshToken");
    if (!jwtUtil.validateToken(refreshToken)) {
        return new ResponseMsg("401", "Refresh Token 已过期", null);
    }

    String username = jwtUtil.getUsernameFromToken(refreshToken);

    // 检查 Redis 中是否存在 refreshToken
    String refreshKey = "user:" + username + ":refresh";
    String redisRefresh = redisTemplate.opsForValue().get(refreshKey);
    if (!refreshToken.equals(redisRefresh)) {
        return new ResponseMsg("403", "非法刷新请求", null);
    }

    // 重新生成新的 token / refreshToken
    String newToken = jwtUtil.generateToken(username);
    String newRefresh = jwtUtil.generateRefreshToken(username);

    long expireSeconds = jwtUtil.getExpiration() / 1000;
    redisTemplate.opsForValue().set("user:" + username + ":token", newToken, expireSeconds, TimeUnit.SECONDS);
    redisTemplate.opsForValue().set("user:" + username + ":refresh", newRefresh, expireSeconds * 2, TimeUnit.SECONDS);

    Map<String, Object> data = new HashMap<>();
    data.put("token", newToken);
    data.put("refreshToken", newRefresh);
    String permsKey = "user:" + username + ":permissions";
    Boolean hasKey = redisTemplate.hasKey(permsKey);
    if (Boolean.TRUE.equals(hasKey)) {
        redisTemplate.expire(permsKey, expireSeconds, TimeUnit.SECONDS);
    } else {
        List<String> apiPaths = userMapper.getApiPathsByUser(username);
        redisTemplate.opsForValue().set(permsKey, JSON.toJSONString(apiPaths), expireSeconds, TimeUnit.SECONDS);
    }
    return new ResponseMsg("200", "刷新成功", data);
}
    @Override
    public ResponseMsg selectUserByMap(Map<String, Object> map) {
        ResponseMsg responseMsg = new ResponseMsg();
        responseMsg.setCode("500");
        List<User> userList = userMapper.selectUserByMap(map);

        responseMsg.setData(userList);
        responseMsg.setCode("200");
        return responseMsg;
    }
}